package org.liziyi.huffman.gui;

import org.liziyi.huffman.algorithm.HuffmanAlgorithm;
import org.liziyi.huffman.config.Config;
import org.liziyi.huffman.utils.PaintUtils;

import javax.swing.*;
import java.awt.*;

/**
 * 自定义画板，用来绘制Huffman树
 *
 * @author liziyi
 */
public class PaintHuffmanTreeJPanel extends JPanel {
    private HuffmanAlgorithm.Node root;
    // huffman树的层数
    private int layer;
    // huffman树大小因子
    private float sizeScale;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (root == null) return;
        // 绘制Huffman树
        paintTree(g);
    }

    /**
     * 注入Huffman树信息
     *
     * @param root
     * @param layer
     */
    public void injectHuffmanTreeInfo(HuffmanAlgorithm.Node root, int layer, float sizeScale) {
        this.root = root;
        this.layer = layer;
        this.sizeScale = sizeScale;
    }

    private void paintTree(Graphics g) {
        Graphics2D graphics2D = (Graphics2D) g;
        // 开启抗锯齿（线条更润滑）
        graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2D.setStroke(new BasicStroke(2));
        graphics2D.scale(sizeScale, sizeScale);
        // 递归画树
        dfs(root, 1, graphics2D,
                Config.treeBasePositionX + (int) Math.pow(2, layer - 1) * Config.treeNodeBaseSize - Config.treeNodeBaseSize / 2,
                Config.treeBasePositionY + Config.treeNodeBaseSize / 2);
        // 设置面板大小
        setPreferredSize(new Dimension(
                (int) ((Config.treeNodeBaseSize * (Math.pow(2, layer) - 1)) * sizeScale) + 1,
                (int) (((2 * layer - 1) * Config.treeNodeBaseSize) * sizeScale) + 1
        ));
        // 更新滚动条
        this.getParent().revalidate();
        this.getParent().repaint();
        g.dispose();
    }

    private void dfs(HuffmanAlgorithm.Node node, int layer, Graphics2D g2d, int x, int y) {
        int nextX, nextY;
        nextY = y + distY();
        if (node.left != null) {
            nextX = x - distX(layer);
            PaintUtils.drawLine(g2d, x, y, nextX, nextY);
            dfs(node.left, layer + 1, g2d, nextX, nextY);
        }
        if (node.right != null) {
            nextX = x + distX(layer);
            PaintUtils.drawLine(g2d, x, y, nextX, nextY);
            dfs(node.right, layer + 1, g2d, nextX, nextY);
        }
        PaintUtils.drawCircle(g2d, x, y);
        if(node.ch=='\n'){
            PaintUtils.drawWord(g2d, "\\n", x, y);
        } else if (node.ch == '\t'){
            PaintUtils.drawWord(g2d, "\\t", x, y);
        } else{
            PaintUtils.drawWord(g2d, node.ch + "", x, y);
        }
    }

    private int distX(int l) {
        return (int) Math.pow(2, layer - l - 1) * Config.treeNodeBaseSize;
    }

    private int distY() {
        return 2 * Config.treeNodeBaseSize;
    }

    public void changeSizeScale(float sizeScale) {
        this.sizeScale *= sizeScale;
    }

}
